package com.yfp.operation.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfp.common.core.utils.bean.BeanUtils;
import com.yfp.operation.domain.ComboDO;
import com.yfp.operation.domain.DeviceComboPlanNumDO;
import com.yfp.operation.domain.MachineDamageDetailDO;
import com.yfp.operation.domain.dto.ComboSaleDataDTO;
import com.yfp.operation.domain.vo.AmtVO;
import com.yfp.operation.domain.vo.ComboSaleDataVO;
import com.yfp.operation.domain.vo.ComboSaleInfoDataVO;
import com.yfp.operation.domain.vo.ComboSaleInfoVO;
import com.yfp.operation.mapper.ComboMapper;
import com.yfp.operation.mapper.DeviceComboPlanNumMapper;
import com.yfp.operation.mapper.OrderListMapper;
import com.yfp.operation.service.ComboService;
import com.yfp.operation.service.MachineDamageDetailService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 * @description 针对表【combo(套餐表)】的数据库操作Service实现
 * @createDate 2024-04-24 14:17:39
 */
@Slf4j
@Service
public class ComboServiceImpl extends ServiceImpl<ComboMapper, ComboDO> implements ComboService {

    @Resource
    private ComboMapper comboMapper;
    @Resource
    private OrderListMapper orderListMapper;
    @Resource
    private DeviceComboPlanNumMapper deviceComboPlanNumMapper;
    @Resource
    private MachineDamageDetailService machineDamageDetailService;

    /**
     * 根据套餐id查询套餐
     *
     * @param comboIds
     * @return
     */
    @Override
    public List<ComboDO> queryByIds(List<String> comboIds) {
        if (CollUtil.isEmpty(comboIds)) {
            return Collections.emptyList();
        }

        LambdaQueryWrapper<ComboDO> query = Wrappers.lambdaQuery(ComboDO.class);
        query.in(ComboDO::getComboId, comboIds);
        return this.list(query);
    }

    @Override
    public String getName(String key) {
        return comboMapper.getName(key);
    }

    @Override
    public List<ComboDO> findByComboIds(List<String> comboIds) {
        return comboMapper.findByComboIds(comboIds);
    }

    /**
     * 套餐销售数据
     *
     * @param comboSaleDataDTO
     * @return
     */
    @Override
    public List<ComboSaleDataVO> comboSaleData(ComboSaleDataDTO comboSaleDataDTO) {
        List<ComboSaleDataVO> list = comboMapper.comboSaleData(comboSaleDataDTO);
        return list;
    }

    /**
     * 数据补全
     *
     * @param list
     * @param comboSaleDataDTO
     * @return
     */
    @Override
    public List<ComboSaleDataVO> complementSaleData(List<ComboSaleDataVO> list, ComboSaleDataDTO comboSaleDataDTO) {

        if (CollUtil.isEmpty(list)) {
            return list;
        }


        List<String> machineIds = list.stream().map(item -> item.getMachineId()).toList();
        comboSaleDataDTO.setMachineIdList(machineIds);

        List<ComboSaleDataVO> grantDateList = deviceComboPlanNumMapper.grantDate(machineIds, comboSaleDataDTO.getStartTime(), comboSaleDataDTO.getEndTime());
        List<ComboSaleDataVO> grantNumList = deviceComboPlanNumMapper.grantNum(grantDateList);
        Map<String, Integer> grantNumMap = grantNumList.stream().collect(Collectors.toMap(ComboSaleDataVO::getMachineId, ComboSaleDataVO::getGrantNum));

        List<MachineDamageDetailDO> comboSaleDataVOS = machineDamageDetailService.lossDate(machineIds, comboSaleDataDTO.getStartTime(), comboSaleDataDTO.getEndTime());
        // 查询每个设备下，每天创建时间最小的数据列表集合，统计分组下reportNum数量和
        Map<String, Integer> lossNumMap = comboSaleDataVOS.stream().collect(Collectors.groupingBy(MachineDamageDetailDO::getMachineId, Collectors.collectingAndThen(Collectors.groupingBy(item -> DateUtil.format(item.getCreateTime(), DatePattern.NORM_DATE_PATTERN), TreeMap::new, Collectors.collectingAndThen(Collectors.toList(), item -> {
            Optional<MachineDamageDetailDO> minCreateTime = item.stream().min(Comparator.comparing(MachineDamageDetailDO::getCreateTime));
            if (minCreateTime.isPresent()) {
                MachineDamageDetailDO machineDamageDetailDO = minCreateTime.get();
                return item.stream().filter(dt -> dt.getCreateTime().equals(machineDamageDetailDO.getCreateTime())).mapToInt(MachineDamageDetailDO::getReportNum).sum();
            } else {
                return 0;
            }
        })), map -> map.values().stream().mapToInt(Integer::intValue).sum())));
        List<ComboSaleDataVO> comboSaleDataVOList = comboMapper.complementSaleData(comboSaleDataDTO);

        Map<String, ComboSaleDataVO> map = comboSaleDataVOList.stream().collect(Collectors.toMap(ComboSaleDataVO::getMachineId, Function.identity()));

        for (ComboSaleDataVO saleDataVO : list) {
            saleDataVO.setSaleNum(0);
            saleDataVO.setMachineSaleNum(0);
            saleDataVO.setAppSaleNum(0);
            saleDataVO.setSaleMoney(BigDecimal.valueOf(0.00));
            saleDataVO.setRefundNum(0);
            saleDataVO.setNotTakeNum(0);
            saleDataVO.setSellRate(BigDecimal.valueOf(0.00));
            saleDataVO.setGrantNum(0);
            saleDataVO.setLossNum(0);
            saleDataVO.setLossRate(BigDecimal.valueOf(0.00));
            if (grantNumMap.containsKey(saleDataVO.getMachineId())) {
                saleDataVO.setGrantNum(grantNumMap.get(saleDataVO.getMachineId()));
                if (lossNumMap.containsKey(saleDataVO.getMachineId())) {
                    saleDataVO.setLossNum(lossNumMap.get(saleDataVO.getMachineId()));
                    BigDecimal multiply = BigDecimal.valueOf(saleDataVO.getLossNum()).divide(BigDecimal.valueOf(saleDataVO.getGrantNum()), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
                    saleDataVO.setLossRate(multiply);
                }
            }
            if (map.containsKey(saleDataVO.getMachineId())) {
                ComboSaleDataVO comboSaleDataVO = map.get(saleDataVO.getMachineId());
                if (comboSaleDataVO.getSaleNum() != null) {
                    saleDataVO.setSaleNum(comboSaleDataVO.getSaleNum());
                }
                if (comboSaleDataVO.getMachineSaleNum() != null) {
                    saleDataVO.setMachineSaleNum(comboSaleDataVO.getMachineSaleNum());
                }

                if (comboSaleDataVO.getAppSaleNum() != null) {
                    saleDataVO.setAppSaleNum(comboSaleDataVO.getAppSaleNum());
                }

                if (comboSaleDataVO.getSaleMoney() != null) {
                    saleDataVO.setSaleMoney(comboSaleDataVO.getSaleMoney());
                }

                if (comboSaleDataVO.getRefundNum() != null) {
                    saleDataVO.setRefundNum(comboSaleDataVO.getRefundNum());
                }

                if (comboSaleDataVO.getNotTakeNum() != null) {
                    saleDataVO.setNotTakeNum(comboSaleDataVO.getNotTakeNum());
                }

                BigDecimal multiply = BigDecimal.valueOf(100);
                if (saleDataVO.getGrantNum() != 0) {
                    multiply = BigDecimal.valueOf(comboSaleDataVO.getSaleNum()).divide(BigDecimal.valueOf(saleDataVO.getGrantNum()), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
                }
                saleDataVO.setSellRate(multiply);
            }
            saleDataVO.setNotSaleNum(saleDataVO.getGrantNum() - saleDataVO.getSaleNum());
        }
        return list;
    }

    /**
     * 套餐数据总览
     *
     * @param comboSaleDataDTO
     * @return
     */
    @Override
    public ComboSaleDataVO comboDataTotal(ComboSaleDataDTO comboSaleDataDTO) {

        List<ComboSaleDataVO> list = comboMapper.comboSaleData(comboSaleDataDTO);
        if (CollUtil.isEmpty(list)) {
            return new ComboSaleDataVO();
        }

//        Integer grantNum = list.stream().mapToInt(ComboSaleDataVO::getGrantNum).sum();

//        int grantNum = list.stream()
//                .mapToInt(obj -> Optional.ofNullable(obj)
//                        .map(ComboSaleDataVO::getGrantNum)
//                        .orElse(0)) // 如果obj为null，则返回0
//                .sum(); // 累加所有值


        List<String> machineIds = list.stream().map(item -> item.getMachineId()).toList();

        List<ComboSaleDataVO> grantDateList = deviceComboPlanNumMapper.grantDate(machineIds, comboSaleDataDTO.getStartTime(), comboSaleDataDTO.getEndTime());
        List<ComboSaleDataVO> grantNumList = deviceComboPlanNumMapper.grantNum(grantDateList);
        int grantNum = grantNumList.stream().mapToInt(ComboSaleDataVO::getGrantNum).sum();


        comboSaleDataDTO.setMachineIdList(machineIds);

        ComboSaleDataVO comboSaleDataVO = comboMapper.comboDataTotal(comboSaleDataDTO);

        comboSaleDataVO.setGrantNum(grantNum);
        comboSaleDataVO.setNotSaleNum(grantNum - comboSaleDataVO.getSaleNum());

        return comboSaleDataVO;
    }

    /**
     * 套餐销售详情
     *
     * @param comboSaleDataDTO
     * @return
     */
    @Override
    public List<ComboSaleDataVO> comboSaleInfo(ComboSaleDataDTO comboSaleDataDTO) {
        if (comboSaleDataDTO.getStartTime() == null) {
            comboSaleDataDTO.setStartTime(new Date(2000 - 1900, 0, 1));
        }
        if (comboSaleDataDTO.getEndTime() == null) {
            comboSaleDataDTO.setEndTime(new Date(2050 - 1900, 0, 1));
        }
        List<ComboSaleDataVO> list = comboMapper.comboSaleInfo(comboSaleDataDTO);
        return list;
    }

    /**
     * 套餐销售详情数据补全
     *
     * @param list
     * @return
     */
    @Override
    public List<ComboSaleInfoVO> complementSaleInfo(List<ComboSaleDataVO> list, ComboSaleDataDTO comboSaleDataDTO) {

        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }

        // 获取投放量
        List<DeviceComboPlanNumDO> createTimeDOS = deviceComboPlanNumMapper.getCreateTime(list, comboSaleDataDTO.getStartTime(), comboSaleDataDTO.getEndTime(), comboSaleDataDTO.getMachineId());

        List<DeviceComboPlanNumDO> comboPlanNumDOS = deviceComboPlanNumMapper.getComboNum(createTimeDOS);

        Map<String, DeviceComboPlanNumDO> planNumDOMap = new HashMap<>();
        if (!CollUtil.isEmpty(comboPlanNumDOS)) {
            // 转换map
            planNumDOMap = comboPlanNumDOS.stream().collect(Collectors.toMap(p -> p.getMachineId() + "-" + p.getComboId() + "-" + p.getCreateTime(), p -> p));
        }

        // 销售金额
        List<AmtVO> amts = orderListMapper.getAmt(list);
        Map<String, AmtVO> amtMap = new HashMap<>();
        if (!CollUtil.isEmpty(amts)) {
            // 转换map
            amtMap = amts.stream().collect(Collectors.toMap(p -> p.getMachineId() + "-" + p.getComboId() + "-" + p.getOrderTime(), p -> p));
        }

        log.info("投放map:{}", comboPlanNumDOS);

        HashMap<Date, ComboSaleInfoVO> map = new HashMap<>();

        for (ComboSaleDataVO saleDataVO : list) {

            // 投放量赋值
            saleDataVO.setGrantNum(0);
            String key = comboSaleDataDTO.getMachineId() + "-" + saleDataVO.getComboId() + "-" + saleDataVO.getOrderTime();
            if (!CollUtil.isEmpty(planNumDOMap) && planNumDOMap.containsKey(key)) {
                DeviceComboPlanNumDO deviceComboPlanNumDO = planNumDOMap.get(key);
                // 投放量
                saleDataVO.setGrantNum(deviceComboPlanNumDO.getComboNum());
                if (deviceComboPlanNumDO.getComboNum() != null) {
                    saleDataVO.setGrantNum(deviceComboPlanNumDO.getComboNum());
                }
            }


            // 未售份数
            saleDataVO.setNotSaleNum(saleDataVO.getGrantNum() - saleDataVO.getSaleNum());
            // 售卖率
            BigDecimal sellRate = BigDecimal.valueOf(0);
            if (saleDataVO.getGrantNum() != 0) {
                sellRate = BigDecimal.valueOf(saleDataVO.getSaleNum()).divide(BigDecimal.valueOf(saleDataVO.getGrantNum()), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            }
            saleDataVO.setComboSaleRate(sellRate);


            if (!CollUtil.isEmpty(amtMap) && amtMap.containsKey(key)) {
                AmtVO amtVO = amtMap.get(key);
                saleDataVO.setUnitPrice(amtVO.getMoney());
            }

            BigDecimal unitPrice = BigDecimal.valueOf(0.00);
            if (saleDataVO.getSaleNum() != 0) {
                unitPrice = saleDataVO.getSaleMoney().divide(BigDecimal.valueOf(saleDataVO.getSaleNum()), 2, RoundingMode.HALF_UP);
            }
            saleDataVO.setUnitPrice(unitPrice);

            ComboSaleInfoDataVO comboSaleInfoDataVO = new ComboSaleInfoDataVO();
            // 拷贝属性相同的数据到新对象
            BeanUtils.copyBeanProp(comboSaleInfoDataVO, saleDataVO);

            if (map.containsKey(saleDataVO.getOrderTime())) {
                ComboSaleInfoVO infoVO = map.get(saleDataVO.getOrderTime());
                infoVO.setSaleNum(infoVO.getSaleNum() + saleDataVO.getSaleNum());
                infoVO.setSaleMoney(infoVO.getSaleMoney().add(saleDataVO.getSaleMoney()));
                infoVO.getSaleDataVOS().add(comboSaleInfoDataVO);
            } else {
                ComboSaleInfoVO infoVO = new ComboSaleInfoVO();
                ArrayList<ComboSaleInfoDataVO> dataVOS = new ArrayList<>();
                infoVO.setMachineId(comboSaleDataDTO.getMachineId());
                infoVO.setOrderTime(saleDataVO.getOrderTime());
                dataVOS.add(comboSaleInfoDataVO);
                infoVO.setSaleDataVOS(dataVOS);
                infoVO.setSaleNum(saleDataVO.getSaleNum());
                infoVO.setSaleMoney(saleDataVO.getSaleMoney());
                map.put(saleDataVO.getOrderTime(), infoVO);
            }
        }

        List<ComboSaleInfoVO> saleInfoVOS = new ArrayList<>(map.values());
        Collections.sort(saleInfoVOS, Comparator.comparing(ComboSaleInfoVO::getOrderTime));

        for (ComboSaleInfoVO saleInfoVO : saleInfoVOS) {
            Date orderTime = saleInfoVO.getOrderTime();
            Calendar instance = Calendar.getInstance();
            instance.setTime(orderTime);
            instance.add(Calendar.DAY_OF_MONTH, -7);
            Date time = instance.getTime();

            instance.setTime(orderTime);
            instance.add(Calendar.DAY_OF_MONTH, -1);
            Date time1 = instance.getTime();

            // 上周数据
            ComboSaleDataVO saleDataVO = orderListMapper.statisticsMoneyAndAmount(comboSaleDataDTO.getMachineId(), time);
            // 昨天数据
            ComboSaleDataVO saleDataVO1 = orderListMapper.statisticsMoneyAndAmount(comboSaleDataDTO.getMachineId(), time1);
            // 价格中位数
            BigDecimal moneyMedian = orderListMapper.getMoneyMedian(comboSaleDataDTO.getMachineId(), orderTime);

            // 已售份数同比
            BigDecimal saleNumRate = BigDecimal.valueOf(100);
            if (saleDataVO.getSaleNum() != 0) {
                saleNumRate = BigDecimal.valueOf(saleInfoVO.getSaleNum() - saleDataVO.getSaleNum()).divide(BigDecimal.valueOf(saleDataVO.getSaleNum()), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            }


            // 已售份数环比
            BigDecimal saleNumLoopRate = BigDecimal.valueOf(100);
            if (saleDataVO1.getSaleNum() != 0) {
                saleNumLoopRate = BigDecimal.valueOf(saleInfoVO.getSaleNum() - saleDataVO1.getSaleNum()).divide(BigDecimal.valueOf(saleDataVO1.getSaleNum()), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            }


            // 已售金额同比
            BigDecimal saleMoneyRate = BigDecimal.valueOf(100);
            if (saleDataVO.getSaleMoney().compareTo(BigDecimal.valueOf(0)) != 0) {
                saleMoneyRate = saleInfoVO.getSaleMoney().subtract(saleDataVO.getSaleMoney()).divide(saleDataVO.getSaleMoney(), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            }


            // 已售金额环比
            BigDecimal saleMoneyLoopRate = BigDecimal.valueOf(100);
            if (saleDataVO1.getSaleMoney().compareTo(BigDecimal.valueOf(0)) != 0) {
                saleMoneyLoopRate = saleInfoVO.getSaleMoney().subtract(saleDataVO1.getSaleMoney()).divide(saleDataVO1.getSaleMoney(), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            }

            saleInfoVO.setSaleNumRate(saleNumRate);
            saleInfoVO.setSaleNumLoopRate(saleNumLoopRate);
            saleInfoVO.setSaleMoneyRate(saleMoneyRate);
            saleInfoVO.setSaleMoneyLoopRate(saleMoneyLoopRate);
            saleInfoVO.setMoneyMedian(moneyMedian);
        }
        return saleInfoVOS;
    }


}




